'''
Description: 
Author: notplus
Date: 2021-12-09 09:53:34
LastEditors: notplus
LastEditTime: 2021-12-14 18:19:00
FilePath: /main.py

Copyright (c) 2021 notplus
'''

import os
import pickle
from datetime import datetime, timedelta

import utils


class Record(object):
    def __init__(self, lat, lng, time):
        self.lat = lat
        self.lng = lng
        self.time = time

    def parse_record(raw_record):
        array = raw_record.split(',')

        lat = float(array[0])
        lng = float(array[1])
        time = datetime.fromisoformat(array[5] + ' ' + array[6][:-1])
        # GMT -> CST
        time += timedelta(hours=8)

        return Record(lat, lng, time)


class StayPoint(object):
    def __init__(self, lat, lng, arv_t, lev_t) -> None:
        self.lat = lat
        self.lng = lng
        self.arv_t = arv_t
        self.lev_t = lev_t
        self.id = -1


class Trajectory(object):
    def __init__(self, records) -> None:
        self.records = records
        self.stay_points = []
        self.records.sort(key=lambda rec: rec.time)

    # compute stay point by strict way (i -> j - 1)
    def compute_stay_point_strict(self, distance_thres, time_thres):
        i, point_num = 0, len(self.records)

        while i < point_num:
            j = i + 1
            while j < point_num:
                dist = utils.compute_dist(self.records[i], self.records[j])
                if dist > distance_thres:
                    delta_t = self.records[j-1].time - self.records[i].time
                    if delta_t > time_thres:
                        lat, lng = utils.compute_mean_lat_lng(
                            self.records[i:j])
                        stay_point = StayPoint(
                            lat, lng, self.records[i].time, self.records[j-1].time)
                        self.stay_points.append(stay_point)
                    i = j
                    break
                j = j + 1
            if j == point_num:
                j -= 1
                delta_t = self.records[j].time - self.records[i].time

                if delta_t > time_thres:
                    lat, lng = utils.compute_mean_lat_lng(
                        self.records[i:j+1])
                    stay_point = StayPoint(
                        lat, lng, self.records[i].time, self.records[j].time)
                    self.stay_points.append(stay_point)
                break

    # compute stay point by smooth way (i -> j) from Zheng et al. (2011)
    def compute_stay_point_smooth(self, distance_thres, time_thres):
        i, point_num = 0, len(self.records)

        while i < point_num:
            j = i + 1
            while j < point_num:
                dist = utils.compute_dist(self.records[i], self.records[j])
                if dist > distance_thres:
                    delta_t = self.records[j].time - self.records[i].time
                    if delta_t > time_thres:
                        lat, lng = utils.compute_mean_lat_lng(
                            self.records[i:j])
                        stay_point = StayPoint(
                            lat, lng, self.records[i].time, self.records[j].time)
                        if stay_point.arv_t > datetime(2010, 1, 1) and stay_point.arv_t < datetime(2011, 9, 1) and \
                                stay_point.lng < 117.4 and stay_point.lng > 115.7 and stay_point.lat < 41.6 and stay_point.lat > 39.4:
                            if stay_point.arv_t > datetime(2011, 7, 1):
                                print('123')
                            self.stay_points.append(stay_point)
                    i = j
                    break
                j = j + 1
            if j == point_num:
                j -= 1
                delta_t = self.records[j].time - self.records[i].time

                if delta_t > time_thres:
                    lat, lng = utils.compute_mean_lat_lng(
                        self.records[i:j+1])
                    stay_point = StayPoint(
                        lat, lng, self.records[i].time, self.records[j].time)
                    if stay_point.arv_t > datetime(2010, 1, 1) and stay_point.arv_t < datetime(2011, 9, 1) and \
                                stay_point.lng < 117.4 and stay_point.lng > 115.7 and stay_point.lat < 41.6 and stay_point.lat > 39.4:
                        self.stay_points.append(stay_point)
                break

    def clear_records(self):
        self.records = []


class User(object):
    def __init__(self, id, traj):
        self.id = id
        self.trajs = traj


class ActivityCluster(object):
    def __init__(self, activities, next_activities) -> None:
        self.activities = activities
        self.next_activities = next_activities
        self.arv_t = sum([act.arv_t - act.arv_t.replace(hour=0, minute=0, second=0, microsecond=0)
                         for act in activities], timedelta()) / len(activities)
        self.lev_t = sum([act.lev_t - act.lev_t.replace(hour=0, minute=0, second=0, microsecond=0)
                         for act in activities], timedelta()) / len(activities)
        self.duration = sum(
            [act.lev_t - act.arv_t for act in activities], timedelta()) / len(activities)
        self.lat, self.lng = utils.compute_mean_lat_lng(activities)


if __name__ == '__main__':
    users = []

    for id in range(128, 129):
        records = []

        for root, dirs, files in os.walk(os.path.join('./Data', '{:0>3d}'.format(id), 'Trajectory')):
            for file_name in files:
                file_path = os.path.join(root, file_name)
                print(file_path)

                with open(file_path, 'r') as f:
                    lines = f.readlines()
                    records += (list(map(Record.parse_record, lines[6:])))

        traj = Trajectory(records)
        traj.compute_stay_point_smooth(200, timedelta(minutes=20))
        traj.clear_records()
        users.append(User(id, traj))

    cnt = 0
    for user in users:
        cnt += len(user.trajs.stay_points)
        print('id: %d, stay point: %d' %
              (user.id, len(user.trajs.stay_points)))

    with open('activity_128_date.pickle', 'wb') as f:
        pickle.dump(users, f)

    print('all point: %d' % cnt)
    print('Done!')
